"""
白名单数据访问层
"""
import re
from typing import List, Optional, Dict, Any
from datetime import datetime
from urllib.parse import urlparse
from motor.motor_asyncio import AsyncIOMotorDatabase
from bson import ObjectId

from src.models.whitelist import (
    WhitelistEntry,
    WhitelistType,
    WhitelistStatus,
    WhitelistMatchResult,
    WhitelistFilter,
    WhitelistStatistics
)


class WhitelistRepository:
    """白名单仓库"""
    
    def __init__(self, db: AsyncIOMotorDatabase):
        """
        初始化白名单仓库
        
        Args:
            db: MongoDB数据库实例
        """
        self.db = db
        self.collection = db["whitelists"]
        self._pattern_cache: Dict[str, re.Pattern] = {}
    
    async def create(self, entry: WhitelistEntry) -> str:
        """
        创建白名单条目
        
        Args:
            entry: 白名单条目
            
        Returns:
            创建的条目ID
        """
        entry_dict = entry.model_dump(exclude={'id'})
        entry_dict['created_at'] = datetime.now()
        entry_dict['updated_at'] = datetime.now()
        
        result = await self.collection.insert_one(entry_dict)
        return str(result.inserted_id)
    
    async def get(self, entry_id: str) -> Optional[WhitelistEntry]:
        """
        获取白名单条目
        
        Args:
            entry_id: 条目ID
            
        Returns:
            白名单条目
        """
        try:
            doc = await self.collection.find_one({"_id": ObjectId(entry_id)})
            if doc:
                doc['id'] = str(doc.pop('_id'))
                return WhitelistEntry(**doc)
        except:
            pass
        return None
    
    async def update(self, entry_id: str, updates: Dict[str, Any]) -> bool:
        """
        更新白名单条目
        
        Args:
            entry_id: 条目ID
            updates: 更新内容
            
        Returns:
            是否成功
        """
        try:
            updates['updated_at'] = datetime.now()
            result = await self.collection.update_one(
                {"_id": ObjectId(entry_id)},
                {"$set": updates}
            )
            return result.modified_count > 0
        except:
            return False
    
    async def delete(self, entry_id: str) -> bool:
        """
        删除白名单条目
        
        Args:
            entry_id: 条目ID
            
        Returns:
            是否成功
        """
        try:
            result = await self.collection.delete_one({"_id": ObjectId(entry_id)})
            return result.deleted_count > 0
        except:
            return False
    
    async def list(self, filter: WhitelistFilter) -> List[WhitelistEntry]:
        """
        列出白名单条目
        
        Args:
            filter: 过滤条件
            
        Returns:
            条目列表
        """
        query = {}
        
        # 构建查询条件
        if filter.type:
            query['type'] = filter.type
        if filter.status:
            query['status'] = filter.status
        if filter.tags:
            query['tags'] = {"$in": filter.tags}
        if filter.created_by:
            query['created_by'] = filter.created_by
        if filter.created_after:
            query['created_at'] = {"$gte": filter.created_after}
        if filter.created_before:
            query.setdefault('created_at', {})['$lte'] = filter.created_before
        if filter.search_text:
            query['$or'] = [
                {'name': {'$regex': filter.search_text, '$options': 'i'}},
                {'value': {'$regex': filter.search_text, '$options': 'i'}},
                {'description': {'$regex': filter.search_text, '$options': 'i'}}
            ]
        
        # 分页
        skip = (filter.page - 1) * filter.page_size
        limit = filter.page_size
        
        cursor = self.collection.find(query).skip(skip).limit(limit)
        entries = []
        async for doc in cursor:
            doc['id'] = str(doc.pop('_id'))
            entries.append(WhitelistEntry(**doc))
        
        return entries
    
    async def match(self, content: str, check_type: Optional[WhitelistType] = None) -> WhitelistMatchResult:
        """
        检查内容是否匹配白名单
        
        Args:
            content: 待检查内容
            check_type: 指定检查类型
            
        Returns:
            匹配结果
        """
        # 获取所有活跃的白名单条目
        query = {'status': WhitelistStatus.ACTIVE}
        if check_type:
            query['type'] = check_type
        
        cursor = self.collection.find(query)
        async for doc in cursor:
            doc['id'] = str(doc.pop('_id'))
            entry = WhitelistEntry(**doc)
            
            # 根据类型进行匹配
            if self._match_entry(content, entry):
                return WhitelistMatchResult(
                    matched=True,
                    entry=entry,
                    match_type=entry.type,
                    confidence=1.0,
                    details={'matched_value': entry.value}
                )
        
        return WhitelistMatchResult(matched=False)
    
    def _match_entry(self, content: str, entry: WhitelistEntry) -> bool:
        """
        匹配单个条目
        
        Args:
            content: 内容
            entry: 白名单条目
            
        Returns:
            是否匹配
        """
        if entry.type == WhitelistType.DOMAIN:
            return self._match_domain(content, entry.value)
        elif entry.type == WhitelistType.URL:
            return self._match_url(content, entry.value)
        elif entry.type == WhitelistType.PATTERN:
            return self._match_pattern(content, entry.value)
        elif entry.type == WhitelistType.SOURCE:
            return entry.value.lower() in content.lower()
        
        return False
    
    def _match_domain(self, content: str, domain: str) -> bool:
        """
        匹配域名
        
        Args:
            content: 内容（可能是URL）
            domain: 域名
            
        Returns:
            是否匹配
        """
        # 尝试解析为URL
        try:
            parsed = urlparse(content)
            if parsed.netloc:
                # 完整域名匹配或子域名匹配
                return (parsed.netloc == domain or 
                       parsed.netloc.endswith('.' + domain))
        except:
            pass
        
        # 直接文本匹配
        return domain in content
    
    def _match_url(self, content: str, url_pattern: str) -> bool:
        """
        匹配URL
        
        Args:
            content: 内容
            url_pattern: URL模式
            
        Returns:
            是否匹配
        """
        # 简单的URL匹配，支持通配符*
        pattern = url_pattern.replace('*', '.*')
        try:
            if pattern not in self._pattern_cache:
                self._pattern_cache[pattern] = re.compile(pattern, re.IGNORECASE)
            return bool(self._pattern_cache[pattern].match(content))
        except:
            return url_pattern in content
    
    def _match_pattern(self, content: str, pattern: str) -> bool:
        """
        匹配正则模式
        
        Args:
            content: 内容
            pattern: 正则表达式
            
        Returns:
            是否匹配
        """
        try:
            if pattern not in self._pattern_cache:
                self._pattern_cache[pattern] = re.compile(pattern, re.IGNORECASE)
            return bool(self._pattern_cache[pattern].search(content))
        except:
            return False
    
    async def batch_create(self, entries: List[WhitelistEntry]) -> List[str]:
        """
        批量创建白名单
        
        Args:
            entries: 条目列表
            
        Returns:
            创建的ID列表
        """
        docs = []
        for entry in entries:
            doc = entry.model_dump(exclude={'id'})
            doc['created_at'] = datetime.now()
            doc['updated_at'] = datetime.now()
            docs.append(doc)
        
        result = await self.collection.insert_many(docs)
        return [str(id) for id in result.inserted_ids]
    
    async def batch_delete(self, entry_ids: List[str]) -> int:
        """
        批量删除白名单
        
        Args:
            entry_ids: ID列表
            
        Returns:
            删除的数量
        """
        object_ids = [ObjectId(id) for id in entry_ids if ObjectId.is_valid(id)]
        if not object_ids:
            return 0
        
        result = await self.collection.delete_many({"_id": {"$in": object_ids}})
        return result.deleted_count
    
    async def update_status(self, entry_id: str, status: WhitelistStatus) -> bool:
        """
        更新状态
        
        Args:
            entry_id: 条目ID
            status: 新状态
            
        Returns:
            是否成功
        """
        return await self.update(entry_id, {'status': status})
    
    async def get_statistics(self) -> WhitelistStatistics:
        """
        获取统计信息
        
        Returns:
            统计信息
        """
        pipeline = [
            {
                "$facet": {
                    "total": [{"$count": "count"}],
                    "by_status": [
                        {"$group": {"_id": "$status", "count": {"$sum": 1}}}
                    ],
                    "by_type": [
                        {"$group": {"_id": "$type", "count": {"$sum": 1}}}
                    ],
                    "by_creator": [
                        {"$group": {"_id": "$created_by", "count": {"$sum": 1}}},
                        {"$limit": 10}
                    ]
                }
            }
        ]
        
        result = await self.collection.aggregate(pipeline).to_list(1)
        
        if result:
            facets = result[0]
            total = facets['total'][0]['count'] if facets['total'] else 0
            
            by_status = {item['_id']: item['count'] for item in facets['by_status']}
            by_type = {item['_id']: item['count'] for item in facets['by_type']}
            by_creator = {item['_id']: item['count'] for item in facets['by_creator']}
            
            return WhitelistStatistics(
                total_entries=total,
                active_entries=by_status.get(WhitelistStatus.ACTIVE, 0),
                inactive_entries=by_status.get(WhitelistStatus.INACTIVE, 0),
                by_type=by_type,
                by_creator=by_creator
            )
        
        return WhitelistStatistics(
            total_entries=0,
            active_entries=0,
            inactive_entries=0
        )
    
    async def ensure_indexes(self):
        """创建索引以优化查询性能"""
        await self.collection.create_index([("type", 1)])
        await self.collection.create_index([("status", 1)])
        await self.collection.create_index([("created_by", 1)])
        await self.collection.create_index([("created_at", -1)])
        await self.collection.create_index([
            ("name", "text"),
            ("value", "text"),
            ("description", "text")
        ])